home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / dkbtrace / pbmplus / source / pbm / atktopbm.c next >
Encoding:
C/C++ Source or Header  |  1992-07-29  |  9.3 KB  |  342 lines

  1. /* atktopbm.c - convert Andrew Toolkit raster object to portable bitmap
  2. **
  3. ** Copyright (C) 1991 by Bill Janssen
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include <stdio.h>
  14. #include "pbm.h"
  15.  
  16. void ReadATKRaster();
  17.  
  18. void
  19. main( argc, argv )
  20.     int argc;
  21.     char *argv[];
  22.     {
  23.     FILE *ifp;
  24.     register bit *bitrow, *bP;
  25.     int rows, cols, row, col, charcount;
  26.     unsigned char *data, mask;
  27.  
  28.     pbm_init ( &argc, argv );
  29.  
  30.     if ( argc > 2 )
  31.     pm_usage( "[raster obj]" );
  32.     
  33.     if ( argc == 2 )
  34.     ifp = pm_openr( argv[1] );
  35.     else
  36.     ifp = stdin;
  37.  
  38.     ReadATKRaster( ifp, &cols, &rows, &data );
  39.  
  40.     pm_close( ifp );
  41.  
  42.     pbm_writepbminit( stdout, cols, rows, 0 );
  43.     bitrow = pbm_allocrow( cols );
  44.  
  45.     for ( row = 0; row < rows; ++row )
  46.     {
  47.     charcount = 0;
  48.     mask = 0x80;
  49.     for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
  50.         {
  51.         if ( charcount >= 8 )
  52.         {
  53.         ++data;
  54.         charcount = 0;
  55.         mask = 0x80;
  56.         }
  57.         *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE;
  58.         ++charcount;
  59.         mask >>= 1;
  60.         }
  61.     ++data;
  62.     pbm_writepbmrow( stdout, bitrow, cols, 0 );
  63.     }
  64.  
  65.     pm_close( stdout );
  66.     exit( 0 );
  67.     }
  68.  
  69. /* readatkraster
  70. **
  71. ** Routine for reading rasters in .raster form.  (BE2 rasters version 2.)
  72. */
  73.  
  74. /* codes for data stream */
  75. #define WHITEZERO    'f'
  76. #define WHITETWENTY    'z'
  77. #define BLACKZERO    'F'
  78. #define BLACKTWENTY    'Z'
  79. #define OTHERZERO    0x1F
  80.  
  81. #define    WHITEBYTE    0x00
  82. #define    BLACKBYTE    0xFF
  83.  
  84. /* error codes (copied from $ANDREW/atk/basics/common/dataobj.ch) */
  85. /* return values from Read */
  86. #define    dataobject_NOREADERROR    0
  87. #define    dataobject_PREMATUREEOF    1
  88. #define    dataobject_NOTBE2DATASTREAM 2 /* backward compatibility */
  89. #define    dataobject_NOTATKDATASTREAM 2 /* preferred version */
  90. #define dataobject_MISSINGENDDATAMARKER 3
  91. #define    dataobject_OBJECTCREATIONFAILED    4
  92. #define dataobject_BADFORMAT 5
  93.  
  94. /* ReadRow(file, row, length) 
  95. ** Reads from 'file' the encoding of bytes to fill in 'row'.  Row will be
  96. ** truncated or padded (with WHITE) to exactly 'length' bytes.
  97. **
  98. ** Returns the code that terminated the row.  This may be
  99. **         '|'      correct end of line
  100. **         '\0'     if the length was satisfied (before a terminator)
  101. **         EOF     if the file ended
  102. **         '\'  '{'     other recognized ends. 
  103. ** The '|' is the expected end and pads the row with WHITE.
  104. ** The '\' and '{' are error conditions and may indicate the
  105. ** beginning of some other portion of the data stream.
  106. ** If the terminator is '\' or '{', it is left at the front of the input.
  107. ** '|' is gobbled up.
  108. */
  109.  
  110. /* macros to generate case entries for switch statement */
  111. #define case1(v) case v
  112. #define case4(v) case v: case (v)+1: case (v)+2: case(v)+3
  113. #define case6(v) case4(v): case ((v)+4): case ((v)+5)
  114. #define case8(v) case4(v): case4((v)+4)
  115.  
  116. static long
  117. ReadRow(file, row, length)
  118.     register FILE *file;        /* where to get them from */
  119.     register unsigned char *row;    /* where to put bytes */
  120.     register long length;    /* how many bytes in row must be filled */
  121. {
  122.     /* Each input character is processed by the central loop.  There are 
  123.     ** some input codes which require two or three characters for
  124.     ** completion; these are handled by advancing the state machine.
  125.     ** Errors are not processed; instead the state machine is reset
  126.     ** to the Ready state whenever a character unacceptable to the
  127.     ** current state is read.
  128.     */
  129.     enum stateCode {
  130.         Ready,         /* any input code is allowed */
  131.         HexDigitPending,    /* have seen the first of a hex digit pair */
  132.         RepeatPending,     /* repeat code has been seen:
  133.                    must be followed by two hex digits */
  134.         RepeatAndDigit};    /* have seen repeat code and its first
  135.                    following digit */
  136.     enum stateCode InputState;    /* current state */
  137.     register c;        /* the current input character */
  138.     register long repeatcount = 0;    /* current repeat value */
  139.     register long hexval;    /* current hex value */
  140.     long pendinghex = 0;    /* the first of a pair of hex characters */
  141.     
  142.     /* We cannot exit when length becomes zero because we need to check 
  143.     ** to see if a row ending character follows.  Thus length is checked
  144.     ** only when we get a data generating byte.  If length then is
  145.     ** zero, we ungetc the byte.
  146.     */
  147.  
  148.     InputState = Ready;
  149.     while ((c=getc(file)) != EOF) switch (c) {
  150.  
  151.     case8(0x0):
  152.     case8(0x8):
  153.     case8(0x10):
  154.     case8(0x18):
  155.     case1(' '):
  156.         /* control characters and space are legal and ignored */
  157.         break;
  158.     case1(0x40):    /* '@' */
  159.     case1(0x5B):    /* '[' */
  160.     case4(0x5D):    /*  ']'  '^'  '_'  '`' */
  161.     case4(0x7D):    /* '}'  '~'  DEL  0x80 */
  162.     default:        /* all above 0x80 */
  163.         /* error code:  Ignored at present.  Reset InputState. */
  164.         InputState = Ready;
  165.         break;
  166.  
  167.     case1(0x7B):    /* '{' */
  168.     case1(0x5C):    /* '\\' */
  169.         /* illegal end of line:  exit anyway */
  170.         ungetc(c, file);    /* retain terminator in stream */
  171.         /* DROP THROUGH */
  172.     case1(0x7C):    /* '|' */
  173.         /* legal end of row: may have to pad  */
  174.         while (length-- > 0)
  175.             *row++ = WHITEBYTE;
  176.         return c;
  177.     
  178.     case1(0x21):
  179.     case6(0x22):
  180.     case8(0x28):
  181.         /* punctuation characters: repeat byte given by two
  182.         ** succeeding hex chars
  183.         */
  184.         if (length <= 0) {
  185.             ungetc(c, file);
  186.             return('\0');
  187.         }
  188.         repeatcount = c - OTHERZERO;
  189.         InputState = RepeatPending;
  190.         break;
  191.  
  192.     case8(0x30):
  193.     case8(0x38):
  194.         /* digit (or following punctuation)  -  hex digit */
  195.         hexval = c - 0x30;
  196.         goto hexdigit;
  197.     case6(0x41):
  198.         /* A ... F    -  hex digit */
  199.         hexval = c - (0x41 - 0xA);
  200.         goto hexdigit;
  201.     case6(0x61):
  202.         /* a ... f  - hex digit */
  203.         hexval = c - (0x61 - 0xA);
  204.         goto hexdigit;
  205.  
  206.     case8(0x67):
  207.     case8(0x6F):
  208.     case4(0x77):
  209.         /* g ... z   -   multiple WHITE bytes */
  210.         if (length <= 0) {
  211.             ungetc(c, file);
  212.             return('\0');
  213.         }
  214.         repeatcount = c - WHITEZERO;
  215.         hexval = WHITEBYTE;
  216.         goto store;
  217.     case8(0x47):
  218.     case8(0x4F):
  219.     case4(0x57):
  220.         /* G ... Z   -   multiple BLACK bytes */
  221.         if (length <= 0) {
  222.             ungetc(c, file);
  223.             return('\0');
  224.         }
  225.         repeatcount = c - BLACKZERO;
  226.         hexval = BLACKBYTE;
  227.         goto store;
  228.  
  229. hexdigit:
  230.         /* process a hex digit.  Use InputState to determine
  231.             what to do with it. */
  232.         if (length <= 0) {
  233.             ungetc(c, file);
  234.             return('\0');
  235.         }
  236.         switch(InputState) {
  237.         case Ready:
  238.             InputState = HexDigitPending;
  239.             pendinghex = hexval << 4;
  240.             break;
  241.         case HexDigitPending:
  242.             hexval |= pendinghex;
  243.             repeatcount = 1;
  244.             goto store;
  245.         case RepeatPending:
  246.             InputState = RepeatAndDigit;
  247.             pendinghex = hexval << 4;
  248.             break;
  249.         case RepeatAndDigit:
  250.             hexval |= pendinghex;
  251.             goto store;
  252.         }
  253.         break;
  254.  
  255. store:
  256.         /* generate byte(s) into the output row 
  257.             Use repeatcount, depending on state.  */
  258.         if (length < repeatcount) 
  259.             /* reduce repeat count if it would exceed
  260.                 available space */
  261.             repeatcount = length;
  262.         length -= repeatcount;    /* do this before repeatcount-- */
  263.         while (repeatcount-- > 0)
  264.                 *row++ = hexval;
  265.         InputState = Ready;
  266.         break;
  267.  
  268.     } /* end of while( - )switch( - ) */
  269.     return EOF;
  270. }
  271. #undef case1
  272. #undef case4
  273. #undef case6
  274. #undef case8
  275.  
  276. void
  277. ReadATKRaster(file, rwidth, rheight, destaddr)
  278.      FILE *file;
  279.      unsigned char **destaddr;
  280.      int *rwidth, *rheight;
  281. {
  282.     register unsigned char *byteaddr;    /* where to store next row */
  283.     register long row, rowlen;    /* count rows;  byte length of row */
  284.     long version, options, xscale, yscale;
  285.     long xoffset, yoffset, subwidth, subheight;
  286.     char keyword[6];
  287.     long discardid, objectid;     /* id read for the incoming pixel image */
  288.     long tc;            /* temp */
  289.     long width, height;        /* dimensions of image */
  290.     long result;
  291.  
  292.     if (fscanf(file, "\\begindata{raster,%ld", &discardid) != 1
  293.                 || getc(file) != '}' || getc(file) != '\n')
  294.       pm_error ("input file not Andrew raster object");
  295.  
  296.     fscanf(file, " %d ", &version);
  297.     if (version < 2) 
  298.       pm_error ("version too old to parse");
  299.  
  300.     /* ignore all these features: */
  301.     fscanf(file, " %u %ld %ld %ld %ld %ld %ld",  
  302.         &options, &xscale, &yscale, &xoffset, 
  303.         &yoffset, &subwidth, &subheight);
  304.  
  305.     /* scan to end of line in case this is actually something beyond V2 */
  306.     while (((tc=getc(file)) != '\n') && (tc != '\\') && (tc != EOF)) {}
  307.  
  308.     /* read the keyword */
  309.     fscanf(file, " %5s", keyword);
  310.     if (strcmp(keyword, "bits") != 0)
  311.       pm_error ("keyword is not bits!");
  312.  
  313.     fscanf(file, " %d %d %d ", &objectid, &width, &height);
  314.  
  315.     if (width < 1 || height < 1 || width > 1000000 || height > 1000000) 
  316.       pm_error ("bad width or height");
  317.  
  318.     *rwidth = width;
  319.     *rheight = height;
  320.     rowlen = (width + 7) / 8;
  321.     *destaddr = (unsigned char *) malloc (sizeof(unsigned char) * height *
  322. rowlen);
  323.     for (row = 0;   row < height;   row++)
  324.       {
  325.         long c;
  326.  
  327.         c = ReadRow(file, *destaddr + (row * rowlen), rowlen);
  328.         if (c != '|')
  329.           {
  330.         if (c == EOF)
  331.           pm_error ("premature EOF");
  332.         else
  333.           pm_error ("bad format");
  334.         break;
  335.           }
  336.       }
  337.     while (! feof(file) && getc(file) != '\\') {};    /* scan for \enddata */
  338.     if (fscanf(file, "enddata{raster,%d", &discardid) != 1
  339.         || getc(file) != '}' || getc(file) != '\n')
  340.       pm_error ("missing end-of-object marker");
  341. }
  342.